<?php
namespace app\common\logic;

use app\common\model\FreightConfig;
use app\common\model\FreightRegion;
use app\common\model\FreightTemplate;
use app\common\model\Store;
use app\common\util\TpshopException;
use think\Model;
use think\facade\Db;
/**
 * 运费 逻辑定义
 * Class CatsLogic
 * @package common\Logic
 */
class FreightLogic
{

    /**
     * 进行一系列运算
     * @throws TpshopException
     */
    public function doCalculation($freight_id,$address,$product_price,$totalnum,$totalweight)
    {
        $freight_template = Db::name('freight_template')->where(['template_id' => $freight_id])->find();
        if(!$freight_template){
            return ['status'=>0,'msg'=>'配送方式不存在'];
        }
        if ($this->goods['is_free_shipping'] == 1) {
            $freight_price = 0;
        }else{
            $freightConfig = $this->getFreightConfig($address['district']);
            if($freight_template['pstype']==0){
                //普通快递
                //计算价格
                switch ($freight_template['type']) {
                    case 1:
                        //按重量
                        $total_unit = isset($this->goods['total_weight']) ? $this->goods['total_weight'] :$this->goods['weight'] * $this->goodsNum;//总重量
                        break;
                    default:
                        //按件数
                        $total_unit = $this->goodsNum;
                }
                $freight_price = $this->getFreightPrice($total_unit, $freightConfig);
            }elseif($freight_template['pstype']==1){
                //到店自提
                $freight_price = 0;
            }elseif($freight_template['pstype']==2){
                //同城配送
                $res = $this->checkPeisiongRange($freight_template,$address,$product_price,$totalnum);
                if(!$res['status']){
                    return $res;
                }else{
                    $freight_price = $res['freight_price'];
                }
            }
        }
        return ['status'=>1,'freight_price'=>$freight_price];
    }

    /**
     * 是否支持配送
     * @return bool|true
     */
    public function checkShipping($freight_id=0){
        if($this->goods['is_free_shipping'] == 0){
            $freightConfig = $this->getFreightConfig($freight_id);
            if(empty($freightConfig)){
                return false;
            }else{
                return true;
            }
        }else{
            return true;
        }
    }


    /**
     * 根据总量和配置信息获取运费
     * @param $total_unit
     * @param $freight_config
     * @return mixed
     */
    private function getFreightPrice($total_unit,$freight_config){
        $total_unit = floatval($total_unit);
        if($freight_config && $total_unit > $freight_config['first_unit']){
            if($freight_config['continue_unit']>0){
                $average = ceil(($total_unit-$freight_config['first_unit']) / $freight_config['continue_unit']);
            }else{
                $average = ceil(($total_unit-$freight_config['first_unit']));
            }
            $freight_price = $freight_config['first_money'] + $freight_config['continue_money'] * $average;
        }else{
            $freight_price = $freight_config['first_money']??0;
        }
        return $freight_price;
    }


    /**
     * @param $freightRegion
     * @return array|false|null|\PDOStatement|string|Model
     */
    private function getFreightConfig($region_id,$freight_id=0){
        $freight = Db::name('freight_template')->where('template_id',$freight_id)->find();
        if($freight && $freight['config']){
            $config = json_decode($freight['config'],true);
            foreach($config as $k=>$config){
                if(empty($config['area_ids'])){
                    $area_ids = 0;
                }else{
                    $area_ids = explode(',',$config['area_ids']);
                }
                if(!$area_ids || in_array($region_id,$area_ids)){
                    return $config;
                }
            }
        }
    }


    public function getList($map){
        $lists = Db::name('freight_template')->where($map)->select()->toArray();
        foreach($lists as $k=>$v){
            $storedata = [];
            if($v['pstype']==1){
                $storedata = [
                    [
                        'name' => '门店1',
                        'address' => 'iec',
                        'juli' => '100米'
                    ],
                    [
                        'name' => '门店2',
                        'address' => 'occ',
                        'juli' => '200米'
                    ],
                ];
            }
            $lists[$k]['storedata'] = $storedata;
        }
        return $lists;
    }

    public function checkPeisiongRange($freight,$address,$product_price,$totalnum){
        if($freight['peisong_rangetype'] == 1){
            $pspointsArr = explode(';',$freight['peisong_rangepath']);
            $pspoints = [];
            foreach($pspointsArr as $pspoint){
                $pspointArr = explode(',',$pspoint);
                $pspoints[] = ['lat'=>$pspointArr[1],'lng'=>$pspointArr[0]];
            }
            if($pspoints){
                $rs = $this->is_point_in_polygon(['lat'=>$address['latitude'],'lng'=>$address['longitude']],$pspoints);
                if(!$rs){
                    return ['status'=>0,'freight_price'=>0,'isoutjuli'=>1,'msg'=>'您的收货地址超出配送范围'];
                }
            }
            $juli = getdistance($address['longitude'],$address['latitude'],$freight['peisong_lng2'],$freight['peisong_lat2'],2);
            $freight_peisong_lng = $freight['peisong_lng2'];
            $freight_peisong_lat = $freight['peisong_lat2'];
        }else{
            $juli = getdistance($address['longitude'],$address['latitude'],$freight['peisong_lng'],$freight['peisong_lat'],2);
            if($juli > $freight['peisong_range']/1000){
                return ['status'=>0,'freight_price'=>0,'isoutjuli'=>1,'msg'=>'您的收货地址超出配送范围'];
            }
            $freight_peisong_lng = $freight['peisong_lng'];
            $freight_peisong_lat = $freight['peisong_lat'];
        }
        //配送费 骑行距离
        $bicycl = logic('MapQQ')->getDirectionDistance($address['longitude'],$address['latitude'],$freight_peisong_lng,$freight_peisong_lat,2);
        if($bicycl && $bicycl['status']==1){
            $juli = $bicycl['distance'];
        }else{
            $juli = getdistance($address['longitude'],$address['latitude'],$freight['peisong_lng'],$freight['peisong_lat'],2);
        }
        if($freight['freeset']==1 && $freight['free_price'] <=$product_price){
            $freight_price = 0;
        }else{
            $freight_price = floatval($freight['peisong_fee1']);
            if($juli - floatval($freight['peisong_juli1']) > 0 && floatval($freight['peisong_juli2']) > 0){
                $freight_price += ceil(($juli - floatval($freight['peisong_juli1']))/floatval($freight['peisong_juli2'])) * floatval($freight['peisong_fee2']);
            }
        }
        return ['status'=>1,'freight_price'=>$freight_price];
    }
    //点是否在多边形内
    public static function is_point_in_polygon($point, $pts) {
        $N = count($pts);
        $boundOrVertex = true; //如果点位于多边形的顶点或边上，也算做点在多边形内，直接返回true
        $intersectCount = 0;//cross points count of x
        $precision = 2e-10; //浮点类型计算时候与0比较时候的容差
        $p1 = 0;//neighbour bound vertices
        $p2 = 0;
        $p = $point; //测试点

        $p1 = $pts[0];//left vertex
        for ($i = 1; $i <= $N; ++$i) {//check all rays
            // dump($p1);
            if ($p['lng'] == $p1['lng'] && $p['lat'] == $p1['lat']) {
                return $boundOrVertex;//p is an vertex
            }

            $p2 = $pts[$i % $N];//right vertex
            if ($p['lat'] < min($p1['lat'], $p2['lat']) || $p['lat'] > max($p1['lat'], $p2['lat'])) {//ray is outside of our interests
                $p1 = $p2;
                continue;//next ray left point
            }

            if ($p['lat'] > min($p1['lat'], $p2['lat']) && $p['lat'] < max($p1['lat'], $p2['lat'])) {//ray is crossing over by the algorithm (common part of)
                if($p['lng'] <= max($p1['lng'], $p2['lng'])){//x is before of ray
                    if ($p1['lat'] == $p2['lat'] && $p['lng'] >= min($p1['lng'], $p2['lng'])) {//overlies on a horizontal ray
                        return $boundOrVertex;
                    }

                    if ($p1['lng'] == $p2['lng']) {//ray is vertical
                        if ($p1['lng'] == $p['lng']) {//overlies on a vertical ray
                            return $boundOrVertex;
                        } else {//before ray
                            ++$intersectCount;
                        }
                    } else {//cross point on the left side
                        $xinters = ($p['lat'] - $p1['lat']) * ($p2['lng'] - $p1['lng']) / ($p2['lat'] - $p1['lat']) + $p1['lng'];//cross point of lng
                        if (abs($p['lng'] - $xinters) < $precision) {//overlies on a ray
                            return $boundOrVertex;
                        }

                        if ($p['lng'] < $xinters) {//before ray
                            ++$intersectCount;
                        }
                    }
                }
            } else {//special case when ray is crossing through the vertex
                if ($p['lat'] == $p2['lat'] && $p['lng'] <= $p2['lng']) {//p crossing over p2
                    $p3 = $pts[($i+1) % $N]; //next vertex
                    if ($p['lat'] >= min($p1['lat'], $p3['lat']) && $p['lat'] <= max($p1['lat'], $p3['lat'])) { //p.lat lies between p1.lat & p3.lat
                        ++$intersectCount;
                    } else {
                        $intersectCount += 2;
                    }
                }
            }
            $p1 = $p2;//next ray left point
        }

        if ($intersectCount % 2 == 0) {//偶数在多边形外
            return false;
        } else { //奇数在多边形内
            return true;
        }
    }
}